package utils

import (
	"database/sql"
	"fmt"
	"sync"

	"cashew.com/cashew_common/configs"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/logs"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

// 连接池配置
type dbConfig struct {
	User      string
	Password  string
	Host      string
	Port      string
	Name      string
	Charset   string
	AliasName string
	MaxOpen   int
	MaxIdle   int
}

// 生成DSN字符串
func (c dbConfig) DSN() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true",
		c.User,
		c.Password,
		c.Host,
		c.Port,
		c.Name,
		c.Charset,
	)
}

var (
	// 主数据库实例
	mainDB   *sql.DB
	mainOnce sync.Once
	mainCfg  = dbConfig{
		User:      configs.CashewDBUser,
		Password:  configs.CashewDBPwd,
		Host:      configs.CashewDBHost,
		Port:      configs.CashewDBPort,
		Name:      configs.CashewDBName,
		Charset:   configs.CashewDBCharset,
		AliasName: configs.CashewDBAliasName,
		MaxOpen:   100, // 根据实际负载调整
		MaxIdle:   20,  // 建议MaxIdle <= MaxOpen/2
	}

	// 统计数据库实例
	statDB   *sql.DB
	statOnce sync.Once
	statCfg  = dbConfig{
		User:      configs.CashewStatDBUser,
		Password:  configs.CashewStatDBPwd,
		Host:      configs.CashewStatDBHost,
		Port:      configs.CashewStatDBPort,
		Name:      configs.CashewStatDBName,
		Charset:   configs.CashewStatDBCharset,
		AliasName: configs.CashewStatDBAliasName,
		MaxOpen:   50,
		MaxIdle:   10,
	}

	// admin 数据库实例
	adminDB   *sql.DB
	adminOnce sync.Once
	adminCfg  = dbConfig{
		User:      configs.CashewAdminDBUser,
		Password:  configs.CashewAdminDBPwd,
		Host:      configs.CashewAdminDBHost,
		Port:      configs.CashewAdminDBPort,
		Name:      configs.CashewAdminDBName,
		Charset:   configs.CashewAdminDBCharset,
		AliasName: configs.CashewAdminDBAliasName,
		MaxOpen:   50,
		MaxIdle:   10,
	}
	// admin 数据库实例
	jobsDB   *sql.DB
	jobsOnce sync.Once
	jobsCfg  = dbConfig{
		User:      configs.CashewJobsDBUser,
		Password:  configs.CashewJobsDBPwd,
		Host:      configs.CashewJobsDBHost,
		Port:      configs.CashewJobsDBPort,
		Name:      configs.CashewJobsDBName,
		Charset:   configs.CashewJobsDBCharset,
		AliasName: configs.CashewJobsDBAliasName,
		MaxOpen:   50,
		MaxIdle:   10,
	}

	// ORM注册状态
	ormRegistered = make(map[string]bool) // 记录已注册的数据库别名
	ormRegisterMu sync.Mutex
)

// 初始化数据库连接（通用函数）
func initDatabase(cfg dbConfig) (*sql.DB, error) {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true",
		cfg.User,
		cfg.Password,
		cfg.Host,
		cfg.Port,
		cfg.Name,
		cfg.Charset,
	)

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("数据库连接失败: %w", err)
	}

	if err = db.Ping(); err != nil {
		return nil, fmt.Errorf("数据库Ping失败: %w", err)
	}

	db.SetMaxOpenConns(cfg.MaxOpen)
	db.SetMaxIdleConns(cfg.MaxIdle)
	return db, nil
}

// 获取主库连接（带错误处理）
func GetDB() *sqlx.DB {
	var initErr error
	mainOnce.Do(func() {
		mainDB, initErr = initDatabase(mainCfg)
	})

	if initErr != nil {
		logs.Error("主库 db 初始化失败: %w", initErr)
		return nil
	}

	return sqlx.NewDb(mainDB, "mysql")
}

// 获取统计库连接
func GetStatDB() *sqlx.DB {
	var initErr error
	statOnce.Do(func() {
		statDB, initErr = initDatabase(statCfg)
	})

	if initErr != nil {
		logs.Error("stat db 初始化失败: %w", initErr)
		return nil
	}

	return sqlx.NewDb(statDB, "mysql")
}

// 获取 admin 库连接
func GetAdminDB() *sqlx.DB {
	var initErr error
	adminOnce.Do(func() {
		adminDB, initErr = initDatabase(adminCfg)
	})

	if initErr != nil {
		logs.Error("admin db 初始化失败: %w", initErr)
		return nil
	}

	return sqlx.NewDb(adminDB, "mysql")
}

// 获取 jobs 库连接
func GetJobsDB() *sqlx.DB {
	var initErr error
	jobsOnce.Do(func() {
		jobsDB, initErr = initDatabase(jobsCfg)
	})

	if initErr != nil {
		logs.Error("jobs db 初始化失败: %w", initErr)
		return nil
	}

	return sqlx.NewDb(jobsDB, "mysql")
}

// 注册 db Beego ORM（线程安全）
func GetDBORM() error {
	ormRegisterMu.Lock()
	defer ormRegisterMu.Unlock()

	if ormRegistered[configs.CashewDBName] {
		return nil
	}

	// 确保主库已初始化
	GetDB()

	// 确保主库已初始化
	if mainDB == nil {
		return fmt.Errorf("主库 db 未初始化")
	}

	// 注册驱动
	if err := orm.RegisterDriver("mysql", orm.DRMySQL); err != nil {
		return fmt.Errorf("注册 db 驱动失败: %w", err)
	}

	err := orm.AddAliasWthDB(configs.CashewDBAliasName, "mysql", mainDB)
	if err != nil {
		return fmt.Errorf("注册 db 连接失败: %w", err)
	}

	// 根据环境配置Debug模式
	orm.Debug = configs.EnvName != "release"

	ormRegistered[configs.CashewDBName] = true
	return nil
}

// 注册 statDb Beego ORM（线程安全）
func GetStatDBORM() error {
	ormRegisterMu.Lock()
	defer ormRegisterMu.Unlock()

	if ormRegistered[configs.CashewStatDBName] {
		return nil
	}

	// 确保 stat db 已初始化
	GetStatDB()

	// 确保主库已初始化
	if statDB == nil {
		return fmt.Errorf("stat db 未初始化")
	}

	// 注册驱动
	if err := orm.RegisterDriver("mysql", orm.DRMySQL); err != nil {
		return fmt.Errorf("注册 stat db 驱动失败: %w", err)
	}

	err := orm.AddAliasWthDB(configs.CashewStatDBAliasName, "mysql", statDB)
	if err != nil {
		return fmt.Errorf("注册 stat db 连接失败: %w", err)
	}

	// 根据环境配置Debug模式
	orm.Debug = configs.EnvName != "release"

	ormRegistered[configs.CashewStatDBName] = true
	return nil
}

// 注册 adminDb Beego ORM（线程安全）
func GetAdminDBORM() error {
	ormRegisterMu.Lock()
	defer ormRegisterMu.Unlock()

	if ormRegistered[configs.CashewAdminDBName] {
		return nil
	}

	// 确保 admin db 已初始化
	GetAdminDB()

	// 确保主库已初始化
	if adminDB == nil {
		return fmt.Errorf("admin db 未初始化")
	}

	// 注册驱动
	if err := orm.RegisterDriver("mysql", orm.DRMySQL); err != nil {
		return fmt.Errorf("注册 admin db 驱动失败: %w", err)
	}

	err := orm.AddAliasWthDB(configs.CashewAdminDBAliasName, "mysql", adminDB)
	if err != nil {
		return fmt.Errorf("注册 admin db 连接失败: %w", err)
	}

	// 根据环境配置Debug模式
	orm.Debug = configs.EnvName != "release"

	ormRegistered[configs.CashewAdminDBName] = true
	return nil
}

// 注册 jobsDb Beego ORM（线程安全）
func GetJobsDBORM() error {
	ormRegisterMu.Lock()
	defer ormRegisterMu.Unlock()

	if ormRegistered[configs.CashewJobsDBName] {
		return nil
	}

	// 确保 jobs db 已初始化
	GetJobsDB()

	// 确保主库已初始化
	if jobsDB == nil {
		return fmt.Errorf("jobs db 未初始化")
	}

	// 注册驱动
	if err := orm.RegisterDriver("mysql", orm.DRMySQL); err != nil {
		return fmt.Errorf("注册 jobs db 驱动失败: %w", err)
	}

	err := orm.AddAliasWthDB(configs.CashewJobsDBAliasName, "mysql", jobsDB)
	if err != nil {
		return fmt.Errorf("注册 jobs db 连接失败: %w", err)
	}

	// 根据环境配置Debug模式
	orm.Debug = configs.EnvName != "release"

	ormRegistered[configs.CashewJobsDBName] = true
	return nil
}
